﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections;
using NUnitForVSTS.NUnitTest;
using NUnitTest.UnitTest.Targets;

// We are using multiple namespaces with muliple classes with the same name, different meaning
// Therefore some alliasses to improve clarity
using TestTarget = NUnitTest.UnitTest.Targets;
using Microsoft.VisualStudio.TestTools.Common;
using System.IO;
using System.Reflection;

namespace NUnitForVSTS.NUnitTest.UT
{
    /// <summary>
    /// Summary description for IntegrationTest
    /// </summary>
    [TestClass]
    [Serializable]
    public class IntegrationTest
    {
        /// <summary>
        /// Performs a full integration test.
        /// </summary>
        [TestMethod]
        public void FullIntegrationTest()
        {
            #region place config file
            Type testClassType = typeof(TestTarget.TestAppConfig);
            string configFile = testClassType.Assembly.Location + ".config";
            string oldFile = new Guid().ToString();
            if (File.Exists(configFile))
            {
                File.Move(configFile, oldFile);
            }
            File.WriteAllText(testClassType.Assembly.Location + ".config",
                                @"<?xml version='1.0' encoding='utf-8' ?>
                                <configuration>
                                    <appSettings>
                                        <add key='importantSetting' value='Important value'/>
                                    </appSettings>
                                </configuration>");
            #endregion

            ICollection col;
            using (NUnitTestTip tip = new NUnitTestTip(null))
            {
                col = tip.Load(typeof(TestFailed).Assembly.Location, null, new Warnings());
            }
            Assert.AreEqual(30, col.Count);
            NUnitTestAdapter adapter = new NUnitTestAdapter();

            #region Initialize dummies
            UnitTest[] tests = new UnitTest[col.Count];
            DummyResultSink[] sinks = new DummyResultSink[col.Count];
            col.CopyTo(tests, 0);

            DummyResultSink result = new DummyResultSink();
            DummyRunConfig runConfig = new DummyRunConfig();
            runConfig.TestElements = tests;

            DummyContextAccessor runContextVariables = new DummyContextAccessor();
            runContextVariables.AddStringValue("TestDeploymentDir", Path.GetDirectoryName(typeof(TestFailed).Assembly.Location));

            DummyRunContext runContext = new DummyRunContext();
            runContext.ResultSink = result;
            runContext.RunConfig = runConfig;
            runContext.RunContextVariables = runContextVariables;
            #endregion

            adapter.Initialize(runContext);
            for(int i = 0; i < tests.Length; i++)
            {
                DummyTestContext testContext = new DummyTestContext();
                testContext.RunConfig = runConfig;
                sinks[i] = new DummyResultSink();
                testContext.ResultSink = sinks[i];
                testContext.RunContextVariables = runContextVariables;

               adapter.Run(tests[i], testContext);
            }

            adapter.PreTestRunFinished(runContext);
            adapter.Cleanup();

            for(int i = 0; i < tests.Length; i++)
            {
                string actual = sinks[i].Result.ToString();
                  Assert.IsTrue(actual.Contains(tests[i].Name));
                if (tests[i].Name.Contains("ShouldFail"))
                {
                    Assert.IsFalse(actual.Contains("Error"), actual);
                    Assert.IsFalse(actual.Contains("Passed"), actual);
                    Assert.IsTrue(actual.Contains("Outcome: Failed"),  tests[i].FullyQualifiedClassName + "." + tests[i].Name + " Should have failed, but:" + actual);
                }
                else if (tests[i].Name.Contains("ShouldError"))
                {
                    Assert.IsTrue(actual.Contains("Outcome: Error"), tests[i].FullyQualifiedClassName + "." + tests[i].Name + " Should have Error, but:" + actual);
                }
                else
                {
                    Assert.IsFalse(actual.Contains("Error"), actual);
                    Assert.IsFalse(actual.Contains("Failed"), actual);
                    Assert.IsTrue(actual.Contains("Outcome: Passed"), tests[i].FullyQualifiedClassName + "." + tests[i].Name + " Should have passed, but:" + actual);
                }
            }

            TestResult testResult = null;
            using (NUnitTestTip tip = new NUnitTestTip(null))
            {
                foreach (DummyResultSink sink in sinks)
                {
                    foreach (TestResultMessage message in sink.TestMessages)
                    {
                        testResult = tip.MergeResults(testResult, message);
                    }
                }
            }
            Assert.AreEqual(TestOutcome.Failed, testResult.Outcome, "Endresult should be Failed");
            
            File.Delete(configFile);
            if (File.Exists(oldFile))
            {
                File.Move(oldFile, configFile);
            }
        }

        /// <summary>
        /// Warning Handler
        /// </summary>
        [Serializable]
        private class Warnings : IWarningHandler
        {
            #region IWarningHandler Members

            /// <summary>
            /// Writes the specified sender.
            /// </summary>
            /// <param name="sender">The sender.</param>
            /// <param name="ea">The <see cref="Microsoft.VisualStudio.TestTools.Common.WarningEventArgs"/> instance containing the event data.</param>
            public void Write(object sender, WarningEventArgs ea)
            {
                Console.WriteLine(ea.Warning);
            }

            #endregion
        }
    }
}
